//
// Created on 2023/6/7.
//
// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found,
// please include "napi/native_api.h".

#include "avcodec_napi_utils.h"
#include "avcodec_log.h"
#include <js_native_api.h>
#include <js_native_api_types.h>
#include <string>
namespace OHOS {
namespace Media {

bool AvCodecNapiUtils::getNapiCharArrFromUint8Arr(napi_env env, napi_value value, uint8_t **resultBuf, int bufLen, int &realLen,
                                       bool isCpy) {
    napi_valuetype valueType;
    napi_typeof(env, value, &valueType);
    if (valueType == napi_object) {
        bool isTypedArray = false;
        napi_status status = napi_is_typedarray(env, value, &isTypedArray);
        if (status != napi_ok) {
            AVCODEC_LOGE("NAPI: %{public}s napi_is_typedarray(status:%{public}d) err.", __FUNCTION__, status);
        } else {
            if (isTypedArray) {
                char *buf = nullptr;
                napi_typedarray_type typedArrayType;
                size_t typedArrayLength = 0;
                size_t byteOffset = 0;

                if (isCpy) {
                    status = napi_get_typedarray_info(env,
                                                      value,
                                                      &typedArrayType,
                                                      &typedArrayLength,
                                                      (void **)(&buf),
                                                      nullptr,
                                                      &byteOffset);
                } else {
                    status = napi_get_typedarray_info(env,
                                                      value,
                                                      &typedArrayType,
                                                      &typedArrayLength,
                                                      (void **)resultBuf,
                                                      nullptr,
                                                      &byteOffset);
                }

                if (status != napi_ok) {
                    AVCODEC_LOGE("NAPI: %{public}s napi_get_typedarray_info(status:%{public}d) err.", __FUNCTION__, status);
                    return false;
                }

                if (typedArrayType == napi_uint8_array && typedArrayLength > 0) {
                    realLen = typedArrayLength;
                    if (isCpy && buf != nullptr) {
                        memcpy(*resultBuf, buf, typedArrayLength >= bufLen ? bufLen : typedArrayLength);
                    }
                    return true;
                }
            }
        }
    } else {
        AVCODEC_LOGE("NAPI: %{public}s napi_valuetype(%{public}d) err.", __FUNCTION__, valueType);
    }
    return false;
}

bool AvCodecNapiUtils::getNapiInt64Value(napi_env env, napi_value value, int64_t &result) {
    napi_valuetype valueType;
    napi_typeof(env, value, &valueType);
    if (valueType == napi_number) {
        napi_status status = napi_get_value_int64(env, value, &result);
        if (status != napi_ok) {
            AVCODEC_LOGE("NAPI: %{public}s napi_get_value_int64(status:%{public}d) err.", __FUNCTION__, status);
        } else {
            return true;
        }
    } else {
        AVCODEC_LOGE("NAPI: %{public}s napi_valuetype err.", __FUNCTION__);
    }
    return false;
}

bool AvCodecNapiUtils::getNapiInt32Value(napi_env env, napi_value value, int32_t &result) {
    napi_valuetype valueType;
    napi_typeof(env, value, &valueType);
    if (valueType == napi_number) {
        napi_status status = napi_get_value_int32(env, value, &result);
        if (status != napi_ok) {
            AVCODEC_LOGE("NAPI: %{public}s napi_get_value_int32(status:%{public}d) err.", __FUNCTION__, status);
        } else {
            return true;
        }
    } else {
        AVCODEC_LOGE("NAPI: %{public}s napi_valuetype(%{public}d) err.", __FUNCTION__, valueType);
    }
    return false;
}
std::string AvCodecNapiUtils::getNapiStringValue(napi_env env, napi_value value)
{    
    std::string strValue = "";
    size_t bufLength = 0;
    napi_status status = napi_get_value_string_utf8(env, value, nullptr, 0, &bufLength);
    if (status == napi_ok && bufLength > 0 && bufLength < PATH_MAX) {
         char *buffer = (char *)malloc((bufLength + 1) * sizeof(char));
         CHECK_AND_RETURN_RET_LOG(buffer != nullptr, strValue, "no memory");
         status = napi_get_value_string_utf8(env, value, buffer, bufLength + 1, &bufLength);
         if (status == napi_ok) {
             AVCODEC_LOGD("argument = %{public}s", buffer);
             strValue = buffer;
         }
         free(buffer);
         buffer = nullptr;
     }
     return strValue;
}
bool AvCodecNapiUtils::getObjPropInt32Value(napi_env env, napi_value value, const char *prop, int32_t &outVal)
{
    napi_value num = nullptr;
    napi_status status = napi_get_named_property(env, value, prop, &num);
    if (status != napi_ok || num == nullptr) {
        AVCODEC_LOGE("NAPI:%{public}s napi_get_named_property(%{public}s) err", __FUNCTION__, prop);
        return false;
    } else {
        if (!AvCodecNapiUtils::getNapiInt32Value(env, num, outVal)) {
            AVCODEC_LOGE("NAPI:%{public}s getNapiInt32Value(%{public}s) err", __FUNCTION__, prop);
            return false;
        }
    }
    return true;
}

std::string AvCodecNapiUtils::getObjPropStringValue(napi_env env, napi_value value, const char *prop){
    napi_value str = nullptr;
    napi_status status = napi_get_named_property(env, value, prop, &str);
    if(status != napi_ok || str == nullptr){
        AVCODEC_LOGE("NAPI:%{public}s napi_get_named_property(%{public}s) err", __FUNCTION__, prop);
        return "";
    }
    std::string result = "";
    result = AvCodecNapiUtils::getNapiStringValue(env, str);
    return result;
}
bool AvCodecNapiUtils::createNapiInt32Value(napi_env env, int32_t value, napi_value &result){
    napi_status status = napi_create_int32(env, value, &result);
    if(status != napi_ok){
        AVCODEC_LOGE("NAPI:%{public}s napi_create_int32(%{public}s) err",__FUNCTION__,status);
        return false;
    }
    return true;
}

bool AvCodecNapiUtils::createNapiStringValue(napi_env env, std::string value, napi_value &result){
    napi_status status = napi_create_string_utf8(env, value.c_str(),value.length(), &result);
    if(status != napi_ok){
        AVCODEC_LOGE("NAPI:%{public}s napi_create_string_utf8(%{public}s) err",__FUNCTION__,status);
        return false;
    }
    return true;
}

bool AvCodecNapiUtils::setNapiObjInt32Prop(napi_env env, const char *prop, int32_t value, napi_value &obj){
    napi_value prop_value;
    napi_status status;
    if(!AvCodecNapiUtils::createNapiInt32Value(env, value, prop_value)) return false;
    status = napi_set_named_property(env, obj, prop, prop_value);
    if(status != napi_ok){
        AVCODEC_LOGE("NAPI:%{public}s napi_set_named_property(%{public}s) err",__FUNCTION__,status);
        return false;
    }
}

bool AvCodecNapiUtils::setNapiObjStringProp(napi_env env, const char *prop, std::string value, napi_value &obj){
    napi_value prop_value;
    napi_status status;
    if(!AvCodecNapiUtils::createNapiStringValue(env, value, prop_value)) return false;
    status = napi_set_named_property(env, obj, prop, prop_value);
    if(status != napi_ok){
        AVCODEC_LOGE("NAPI:%{public}s napi_set_named_property(%{public}s) err",__FUNCTION__,status);
        return false;
    }
    return true;
}
bool AvCodecNapiUtils::CreateArrayBuffer(napi_env env, void* src, size_t srcLen, napi_value *res)
{
    if (src == nullptr || srcLen == 0) {
        return false;
    }
    auto status = napi_create_external_arraybuffer(
        env, src, srcLen,
        [](napi_env env, void *data, void *hint) {}, NULL, res);
    if (status != napi_ok) {
        return false;
    }
    return true;
}
bool AvCodecNapiUtils::CreateArrayBuffer1(napi_env env, void* src, size_t srcLen, napi_value *res)
{
    if (src == nullptr || srcLen == 0) {
        return false;
    }
    if (napi_create_arraybuffer(env, srcLen, &src, res) != napi_ok ) {
        return false;
    }
    return true;
}
napi_valuetype AvCodecNapiUtils::getType(napi_env env, napi_value root)
{
    napi_valuetype res = napi_undefined;
    napi_typeof(env, root, &res);
    return res;
}


} // namespace Media
} // namespace OHOS